package org.example.lotterysystem.service.impl;

import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.example.lotterysystem.common.domain.dto.DrawPrizeDTO;
import org.example.lotterysystem.common.domain.dto.ShowWinningRecordsDTO;
import org.example.lotterysystem.common.domain.enums.ActivityPrizeStatusEnum;
import org.example.lotterysystem.common.domain.enums.ActivityStatusEnum;
import org.example.lotterysystem.common.domain.vo.WinningRecordVO;
import org.example.lotterysystem.common.errorcode.ErrorCodeConstants;
import org.example.lotterysystem.common.exception.ServiceException;
import org.example.lotterysystem.common.utils.JacksonUtil;
import org.example.lotterysystem.common.utils.RedisUtil;
import org.example.lotterysystem.mapper.*;
import org.example.lotterysystem.mapper.dataobject.*;
import org.example.lotterysystem.service.DrawPrizeService;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

import static org.example.lotterysystem.common.config.DirectRabbitConfig.EXCHANGE_NAME;
import static org.example.lotterysystem.common.config.DirectRabbitConfig.ROUTING;

@Slf4j
@Service
public class DrawPrizeServiceImpl implements DrawPrizeService {
    private final Long WINNING_RECORDS_TIMEOUT = 60 * 60 * 24 * 2L;
    private final String WINNING_RECORDS_PREFIX = "WINNING_RECORDS_";

    @Resource
    RabbitTemplate rabbitTemplate;

    @Resource
    RedisUtil redisUtil;

    @Resource
    ActivityMapper activityMapper;

    @Resource
    ActivityPrizeMapper activityPrizeMapper;

    @Resource
    UserMapper userMapper;

    @Resource
    PrizeMapper prizeMapper;

    @Resource
    WinningRecordMapper winningRecordMapper;

    /**
     *发消息，消息生产者
     */
    @Override
    public void drawPrize(DrawPrizeDTO drawPrizeDTO) {
        //构造消息体
        Map<String,String> map=new HashMap<>();
        map.put("messageId", String.valueOf(UUID.randomUUID()));
        map.put("messageData", JacksonUtil.writeValueAsString(drawPrizeDTO));

        rabbitTemplate.convertAndSend(EXCHANGE_NAME, ROUTING, map);
    }

    /**
     * 校验抽奖请求是否有效
     */
    @Override
    public boolean checkDrawPrizeParam(DrawPrizeDTO param) {
        //活动和奖品是否存在
        ActivityDO activityDO = activityMapper.selectById(param.getActivityId());
        ActivityPrizeDO activityPrizeDO = activityPrizeMapper.selectByAPId(param.getActivityId(), param.getPrizeId());

        if(activityDO==null && activityPrizeDO==null){
            throw new ServiceException(ErrorCodeConstants.ACTIVITY_OR_PRIZE_IS_EMPTY);
        }
        //活动是否有效
        if (activityDO.getStatus()
                .equalsIgnoreCase(ActivityStatusEnum.COMPLETED.name())) {
            return false;
        }
        //奖品是否有效
        if (activityPrizeDO.getStatus()
                .equalsIgnoreCase(ActivityPrizeStatusEnum.COMPLETED.name())) {
            return false;
        }
        //中奖者人数是否与设置的一致
        if (activityPrizeDO.getPrizeAmount() != param.getWinnerList().size()) {
            return false;
        }
        return true;
    }

    /**
     * 保存中奖者名单
     */
    @Override
    public List<WinningRecordDO> saveWinnerRecords(DrawPrizeDTO param) {
        //查询活动、奖品、人员
        ActivityDO activityDO = activityMapper.selectById(param.getActivityId());
        List<UserDO> userDOList = userMapper.batchSelectByIds(
                param.getWinnerList()
                        .stream()
                        .map(DrawPrizeDTO.Winner::getUserId)
                        .collect(Collectors.toList())
        );
        PrizeDO prizeDO = prizeMapper.selectById(param.getPrizeId());
        ActivityPrizeDO activityPrizeDO =
                activityPrizeMapper.selectByAPId(param.getActivityId(), param.getPrizeId());

        //构造中奖者记录
        List<WinningRecordDO> winningRecordDOList=userDOList.stream()
                .map(userDO -> {
                    WinningRecordDO winningRecordDO = new WinningRecordDO();
                    winningRecordDO.setActivityId(activityDO.getId());
                    winningRecordDO.setActivityName(activityDO.getActivityName());
                    winningRecordDO.setPrizeId(prizeDO.getId());
                    winningRecordDO.setPrizeName(prizeDO.getName());
                    winningRecordDO.setPrizeTier(activityPrizeDO.getPrizeTiers());
                    winningRecordDO.setWinnerId(userDO.getId());
                    winningRecordDO.setWinnerName(userDO.getUserName());
                    winningRecordDO.setWinnerEmail(userDO.getEmail());
                    winningRecordDO.setWinnerPhoneNumber(userDO.getPhoneNumber());
                    winningRecordDO.setWinningTime(param.getWinningTime());
                    return winningRecordDO;
                }).collect(Collectors.toList());
        winningRecordMapper.batchInsert(winningRecordDOList);

        // 缓存中奖者记录
        // 1、缓存奖品维度中奖记录(WinningRecord_activityId_prizeId, winningRecordDOList（奖品维度的中奖名单）)
        cacheWinningRecords(param.getActivityId() + "_" + param.getPrizeId(),
                winningRecordDOList,
                WINNING_RECORDS_TIMEOUT);

        // 2、缓存活动维度中奖记录(WinningRecord_activityId, winningRecordDOList(活动维度的中奖名单))
        // 当活动已完成再去存放活动维度中奖记录
        if (activityDO.getStatus()
                .equalsIgnoreCase(ActivityStatusEnum.COMPLETED.name())) {
            // 查询活动维度的全量中奖记录
            List<WinningRecordDO> allList = winningRecordMapper.selectByActivityId(param.getActivityId());
            cacheWinningRecords(String.valueOf(param.getActivityId()),
                    allList,
                    WINNING_RECORDS_TIMEOUT);
        }

        return winningRecordDOList;

    }

    /**
     * 回滚中奖记录
     */
    @Override
    public void deleteRecords(Long activityId, Long prizeId) {
        if(activityId==null){
            log.warn("回滚中奖记录中的活动Id为空");
            return ;
        }
        //删除数据库的记录
        winningRecordMapper.deleteRecords(activityId,prizeId);
        //删除Redis中的记录
        if (null != prizeId) {
            deleteWinningRecords(activityId + "_" + prizeId);
        }
        deleteWinningRecords(String.valueOf(activityId));
    }

    /**
     *获取抽奖结果
     */
    @Override
    public List<WinningRecordVO> getRecords(ShowWinningRecordsDTO param) {
        //先从缓存中获取
        String key=param.getPrizeId()==null?String.valueOf(param.getActivityId()):param.getActivityId()+"_"+param.getPrizeId();

        List<WinningRecordDO> winningRecords = getWinningRecords(key);

        if(!CollectionUtils.isEmpty(winningRecords)){
            return convertToWinningRecordVOList(winningRecords);
        }

        //查询数据库
        winningRecords = winningRecordMapper.selectByActivityIdOrPrizeId(param.getActivityId(), param.getPrizeId());
        if(CollectionUtils.isEmpty(winningRecords)){
            return Arrays.asList();
        }
        List<WinningRecordVO> winningRecordVOList=convertToWinningRecordVOList(winningRecords);
        //将新查出的数据存入数据库
        cacheWinningRecords(key,winningRecords,WINNING_RECORDS_TIMEOUT);
        return winningRecordVOList;
    }

    private List<WinningRecordVO> convertToWinningRecordVOList(
            List<WinningRecordDO> winningRecordDOList) {
        if (CollectionUtils.isEmpty(winningRecordDOList)) {
            return Arrays.asList();
        }
        return winningRecordDOList.stream()
                .map(winningRecordDO -> {
                    WinningRecordVO winningRecordVO = new WinningRecordVO();
                    winningRecordVO.setWinnerId(winningRecordDO.getWinnerId());
                    winningRecordVO.setWinnerName(winningRecordDO.getWinnerName());
                    winningRecordVO.setPrizeName(winningRecordDO.getPrizeName());
                    winningRecordVO.setPrizeTier(winningRecordDO.getPrizeTier());
                    winningRecordVO.setWinningTime(winningRecordDO.getWinningTime());
                    return winningRecordVO;
                }).collect(Collectors.toList());
    }

    /**
     * 删除Redis中的记录
     */
    private void deleteWinningRecords(String key) {
        try {
            if (redisUtil.hasKey(WINNING_RECORDS_PREFIX + key)) {
                // 存在再删除
                redisUtil.del(WINNING_RECORDS_PREFIX + key);
            }
        } catch (Exception e) {
            log.error("删除中奖记录缓存异常，key:{}", key);
        }
    }

    /**
     *缓存中奖记录
     */
    private void cacheWinningRecords(String key, List<WinningRecordDO> winningRecordDOList, Long time) {
        String str = "";
        try {
            if (!StringUtils.hasText(key)
                    || CollectionUtils.isEmpty(winningRecordDOList)) {
                log.warn("要缓存的内容为空！key:{}, value:{}",
                        key, JacksonUtil.writeValueAsString(winningRecordDOList));
                return;
            }

            str = JacksonUtil.writeValueAsString(winningRecordDOList);
            redisUtil.set(WINNING_RECORDS_PREFIX + key,
                    str,
                    time);
        } catch (Exception e) {
            log.error("缓存中奖记录异常！key:{}, value:{}", WINNING_RECORDS_PREFIX + key, str);
        }
    }

    /**
     * 从缓存中获取中奖记录
     */
    private List<WinningRecordDO> getWinningRecords(String key) {
        try {
            if (!StringUtils.hasText(key)) {
                log.warn("要从缓存中查询中奖记录的key为空！");
                return Arrays.asList();
            }
            String str = redisUtil.get(WINNING_RECORDS_PREFIX + key);
            if (!StringUtils.hasText(str)) {
                return Arrays.asList();
            }

            return JacksonUtil.readListValue(str, WinningRecordDO.class);
        } catch (Exception e) {
            log.error("从缓存中查询中奖记录异常！key:{}", WINNING_RECORDS_PREFIX + key);
            return Arrays.asList();
        }
    }

}
